home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / language / harvest.cpt / Harvest C / Tcl 6.2 / tclEnv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-22  |  11.8 KB  |  512 lines

  1. #ifdef macintosh
  2. #    pragma segment tclEnv
  3. #endif
  4.  
  5. /* 
  6.  * tclEnv.c --
  7.  *
  8.  *    Tcl support for environment variables, including a setenv
  9.  *    procedure.
  10.  *
  11.  * Copyright 1991 Regents of the University of California
  12.  * Permission to use, copy, modify, and distribute this
  13.  * software and its documentation for any purpose and without
  14.  * fee is hereby granted, provided that this copyright
  15.  * notice appears in all copies.  The University of California
  16.  * makes no representations about the suitability of this
  17.  * software for any purpose.  It is provided "as is" without
  18.  * express or implied warranty.
  19.  */
  20.  
  21. #ifndef lint
  22. static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclEnv.c,v 1.7 91/09/23 11:22:21 ouster Exp $ SPRITE (Berkeley)";
  23. #endif /* not lint */
  24.  
  25. #include "tclInt.h"
  26. #include "tclUnix.h"
  27.  
  28. /*
  29.  * The structure below is used to keep track of all of the interpereters
  30.  * for which we're managing the "env" array.  It's needed so that they
  31.  * can all be updated whenever an environment variable is changed
  32.  * anywhere.
  33.  */
  34.  
  35. typedef struct EnvInterp {
  36.     Tcl_Interp *interp;        /* Interpreter for which we're managing
  37.                  * the env array. */
  38.     struct EnvInterp *nextPtr;    /* Next in list of all such interpreters,
  39.                  * or zero. */
  40. } EnvInterp;
  41.  
  42. static EnvInterp *firstInterpPtr;
  43.                 /* First in list of all managed interpreters,
  44.                  * or NULL if none. */
  45.  
  46. static int environSize = 0;    /* Non-zero means that the all of the
  47.                  * environ-related information is malloc-ed
  48.                  * and the environ array itself has this
  49.                  * many total entries allocated to it (not
  50.                  * all may be in use at once).  Zero means
  51.                  * that the environment array is in its
  52.                  * original static state. */
  53. #ifdef THINK_C
  54. static char **environ = NULL;
  55. #endif
  56.  
  57.  
  58. /*
  59.  * Declarations for local procedures defined in this file:
  60.  */
  61.  
  62. static void        EnvInit _ANSI_ARGS_((void));
  63. static char *        EnvTraceProc _ANSI_ARGS_((ClientData clientData,
  64.                 Tcl_Interp *interp, char *name1, char *name2,
  65.                 int flags));
  66. static int        FindVariable _ANSI_ARGS_((char *name, int *lengthPtr));
  67. void            tcl_setenv _ANSI_ARGS_((char *name, char *value));
  68. void            tcl_unsetenv _ANSI_ARGS_((char *name));
  69.  
  70. /*
  71.  *----------------------------------------------------------------------
  72.  *
  73.  * TclSetupEnv --
  74.  *
  75.  *    This procedure is invoked for an interpreter to make environment
  76.  *    variables accessible from that interpreter via the "env"
  77.  *    associative array.
  78.  *
  79.  * Results:
  80.  *    None.
  81.  *
  82.  * Side effects:
  83.  *    The interpreter is added to a list of interpreters managed
  84.  *    by us, so that its view of envariables can be kept consistent
  85.  *    with the view in other interpreters.  If this is the first
  86.  *    call to Tcl_SetupEnv, then additional initialization happens,
  87.  *    such as copying the environment to dynamically-allocated space
  88.  *    for ease of management.
  89.  *
  90.  *----------------------------------------------------------------------
  91.  */
  92.  
  93. void
  94. TclSetupEnv(interp)
  95.     Tcl_Interp *interp;        /* Interpreter whose "env" array is to be
  96.                  * managed. */
  97. {
  98.     EnvInterp *eiPtr;
  99.     int i;
  100.  
  101.     /*
  102.      * First, initialize our environment-related information, if
  103.      * necessary.
  104.      */
  105.  
  106.     if (!environ) {
  107.         environ = (char **) malloc(sizeof(char *));
  108.         environ[0] = NULL;
  109.     }
  110.     
  111.     if (environSize == 0)
  112.         {
  113.         EnvInit();
  114.         }
  115.  
  116.     /*
  117.      * Next, add the interpreter to the list of those that we manage.
  118.      */
  119.  
  120.     eiPtr = (EnvInterp *) ckalloc(sizeof(EnvInterp));
  121.     eiPtr->interp = interp;
  122.     eiPtr->nextPtr = firstInterpPtr;
  123.     firstInterpPtr = eiPtr;
  124.  
  125.     /*
  126.      * Store the environment variable values into the interpreter's
  127.      * "env" array, and arrange for us to be notified on future
  128.      * writes and unsets to that array.
  129.      */
  130.  
  131.     (void) Tcl_UnsetVar2(interp, "env", (char *) NULL, TCL_GLOBAL_ONLY);
  132.     for (i = 0; ; i++) {
  133.         char *p, *p2;
  134.     
  135.         p = environ[i];
  136.         if (p == NULL) {
  137.             break;
  138.             }
  139.         for (p2 = p; *p2 != '='; p2++) {
  140.             /* Empty loop body. */
  141.             }
  142.         *p2 = 0;
  143.         (void) Tcl_SetVar2(interp, "env", p, p2+1, TCL_GLOBAL_ONLY);
  144.         *p2 = '=';
  145.         }
  146.     
  147.     Tcl_TraceVar2(interp, "env", (char *) NULL,
  148.         TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
  149.         EnvTraceProc, (ClientData) NULL);
  150.     }
  151.  
  152. /*
  153.  *----------------------------------------------------------------------
  154.  *
  155.  * FindVariable --
  156.  *
  157.  *    Locate the entry in environ for a given name.
  158.  *
  159.  * Results:
  160.  *    The return value is the index in environ of an entry with the
  161.  *    name "name", or -1 if there is no such entry.   The integer at
  162.  *    *lengthPtr is filled in with the length of name (if a matching
  163.  *    entry is found) or the length of the environ array (if no matching
  164.  *    entry is found).
  165.  *
  166.  * Side effects:
  167.  *    None.
  168.  *
  169.  *----------------------------------------------------------------------
  170.  */
  171.  
  172. static int
  173. FindVariable(name, lengthPtr)
  174.     char *name;            /* Name of desired environment variable. */
  175.     int *lengthPtr;        /* Used to return length of name (for
  176.                  * successful searches) or number of non-NULL
  177.                  * entries in environ (for unsuccessful
  178.                  * searches). */
  179. {
  180.     int i;
  181.     register char *p1, *p2;
  182.  
  183.     for (i = 0, p1 = environ[i]; p1 != NULL; i++, p1 = environ[i])
  184.         {
  185.         for (p2 = name; *p2 == *p1; p1++, p2++)
  186.             ;
  187.         if ((*p1 == '=') && (*p2 == '\0'))
  188.             {
  189.             *lengthPtr = p2 - name;
  190.             return i;
  191.             }
  192.         }
  193.     
  194.     *lengthPtr = i;
  195.     return -1;
  196.     }
  197.  
  198. /*
  199.  *----------------------------------------------------------------------
  200.  *
  201.  * tcl_setenv --
  202.  *
  203.  *    Set an environment variable, replacing an existing value
  204.  *    or creating a _new variable if there doesn't exist a variable
  205.  *    by the given name.
  206.  *
  207.  * Results:
  208.  *    None.
  209.  *
  210.  * Side effects:
  211.  *    The environ array gets updated, as do all of the interpreters
  212.  *    that we manage.
  213.  *
  214.  *----------------------------------------------------------------------
  215.  */
  216.  
  217. void
  218. tcl_setenv(name, value)
  219.     char *name;            /* Name of variable whose value is to be
  220.                  * set. */
  221.     char *value;        /* New value for variable. */
  222. {
  223. int            index, length, nameLength;
  224. char        *p;
  225. EnvInterp    *eiPtr;
  226.  
  227.     if (environSize == 0)
  228.         {
  229.         EnvInit();
  230.         }
  231.  
  232.     /*
  233.     ** Figure out where the entry is going to go.  If the name doesn't
  234.     ** already exist, enlarge the array if necessary to make room.  If
  235.     ** the name exists, free its old entry.
  236.     */
  237.  
  238.     index = FindVariable(name, &length);
  239.     if (index == -1) {
  240.         if ((length+2) > environSize) {
  241.             char **newEnviron;
  242.     
  243.             newEnviron = (char **) ckalloc((unsigned) ((length+5) * sizeof(char *)));
  244.             memcpy((VOID *) newEnviron, (VOID *) environ, length*sizeof(char *));
  245.             ckfree((char *) environ);
  246.             environ = newEnviron;
  247.             environSize = length+5;
  248.             }
  249.         
  250.         index = length;
  251.         environ[index+1] = NULL;
  252.         nameLength = strlen(name);
  253.         }
  254.     else {
  255.         ckfree(environ[index]);
  256.         nameLength = length;
  257.         }
  258.  
  259.     /*
  260.     ** Create a _new entry and enter it into the table.
  261.     */
  262.  
  263.     p = (char *) ckalloc((unsigned) (nameLength + strlen(value) + 2));
  264.     environ[index] = p;
  265.     strcpy(p, name);
  266.     p += nameLength;
  267.     *p = '=';
  268.     strcpy(p+1, value);
  269.  
  270. #ifdef macintosh
  271.     check_environment_set_of_globals(name, value);
  272. #endif
  273.  
  274.     /*
  275.     ** Update all of the interpreters.
  276.     */
  277.     for (eiPtr= firstInterpPtr; eiPtr != NULL; eiPtr = eiPtr->nextPtr) {
  278.         (void) Tcl_SetVar2(eiPtr->interp, "env", name, p+1, TCL_GLOBAL_ONLY);
  279.         }
  280.     }
  281.  
  282. /*
  283.  *----------------------------------------------------------------------
  284.  *
  285.  * tcl_unsetenv --
  286.  *
  287.  *    Remove an environment variable, updating the "env" arrays
  288.  *    in all interpreters managed by us.
  289.  *
  290.  * Results:
  291.  *    None.
  292.  *
  293.  * Side effects:
  294.  *    Interpreters are updated, as is environ.
  295.  *
  296.  *----------------------------------------------------------------------
  297.  */
  298.  
  299. void
  300. tcl_unsetenv(name)
  301.     char *name;            /* Name of variable to remove. */
  302. {
  303.     int index, dummy;
  304.     char **envPtr;
  305.     EnvInterp *eiPtr;
  306.  
  307.     if (environSize == 0) {
  308.         EnvInit();
  309.         }
  310.  
  311.     /*
  312.      * Update the environ array.
  313.      */
  314.  
  315.     index = FindVariable(name, &dummy);
  316.     if (index == -1) {
  317.         return;
  318.            }
  319.     ckfree(environ[index]);
  320.     for (envPtr = environ+index+1; ; envPtr++) {
  321.         envPtr[-1] = *envPtr;
  322.         if (*envPtr == NULL) {
  323.             break;
  324.             }
  325.         }
  326.  
  327.     /*
  328.      * Update all of the interpreters.
  329.      */
  330.  
  331.     for (eiPtr = firstInterpPtr; eiPtr != NULL; eiPtr = eiPtr->nextPtr) {
  332.         (void) Tcl_UnsetVar2(eiPtr->interp, "env", name, TCL_GLOBAL_ONLY);
  333.            }
  334.     
  335.     }
  336.  
  337. /*
  338.  *----------------------------------------------------------------------
  339.  *
  340.  * tcl_getenv --
  341.  *
  342.  *
  343.  * Results:
  344.  *    None.
  345.  *
  346.  * Side effects:
  347.  *
  348.  *----------------------------------------------------------------------
  349.  */
  350.  
  351. char *
  352. tcl_getenv(name)
  353. char        *name;            /* Name of variable to remove. */
  354. {
  355. int        index, dummy;
  356. char    *ptr;
  357.  
  358.     if (environSize == 0)
  359.         EnvInit();
  360.  
  361.     index = FindVariable(name, &dummy);
  362.     
  363.     if (index == -1)
  364.         return "";
  365.     else {
  366.         ptr = strchr(environ[index], '=');
  367.         if (ptr != NULL)
  368.             return ptr + 1;
  369.         else
  370.             return "";
  371.         }
  372.     }
  373.  
  374. /*
  375.  *----------------------------------------------------------------------
  376.  *
  377.  * EnvTraceProc --
  378.  *
  379.  *    This procedure is invoked whenever an environment variable
  380.  *    is modified or deleted.  It propagates the change to the
  381.  *    "environ" array and to any other interpreters for whom
  382.  *    we're managing an "env" array.
  383.  *
  384.  * Results:
  385.  *    Always returns NULL to indicate success.
  386.  *
  387.  * Side effects:
  388.  *    Environment variable changes get propagated.  If the whole
  389.  *    "env" array is deleted, then we stop managing things for
  390.  *    this interpreter (usually this happens because the whole
  391.  *    interpreter is being deleted).
  392.  *
  393.  *----------------------------------------------------------------------
  394.  */
  395.  
  396.     /* ARGSUSED */
  397. static char *
  398. EnvTraceProc(clientData, interp, name1, name2, flags)
  399. ClientData clientData;    /* Not used. */
  400. Tcl_Interp *interp;        /* Interpreter whose "env" variable is
  401.                           * being modified. */
  402. char *name1;            /* Better be "env". */
  403. char *name2;            /* Name of variable being modified, or
  404.                           * NULL if whole array is being deleted. */
  405. int flags;                /* Indicates what's happening. */
  406. {
  407.     /*
  408.     ** First see if the whole "env" variable is being deleted.  If
  409.     ** so, just forget about this interpreter.
  410.     */
  411.  
  412.     if (name2 == NULL) {
  413.         register EnvInterp *eiPtr, *prevPtr;
  414.     
  415.         if ( (flags & (TCL_TRACE_UNSETS|TCL_TRACE_DESTROYED))
  416.                     != (TCL_TRACE_UNSETS|TCL_TRACE_DESTROYED))
  417.             {
  418.             panic("EnvTraceProc called with confusing arguments");
  419.             }
  420.         
  421.         eiPtr = firstInterpPtr;
  422.         if (eiPtr->interp == interp)
  423.             {
  424.             firstInterpPtr = eiPtr->nextPtr;
  425.             }
  426.         else
  427.             {
  428.             for (prevPtr = eiPtr, eiPtr = eiPtr->nextPtr; ;
  429.                 prevPtr = eiPtr, eiPtr = eiPtr->nextPtr)
  430.                 {
  431.                 if (eiPtr == NULL)
  432.                     {
  433.                     panic("EnvTraceProc couldn't find interpreter");
  434.                     }
  435.                 if (eiPtr->interp == interp)
  436.                     {
  437.                     prevPtr->nextPtr = eiPtr->nextPtr;
  438.                     break;
  439.                     }
  440.                 }
  441.             }
  442.         
  443.         ckfree((char *) eiPtr);
  444.         return NULL;
  445.         }
  446.  
  447.     /*
  448.      * If a value is being set, call tcl_setenv to do all of the work.
  449.      */
  450.  
  451.     if (flags & TCL_TRACE_WRITES)
  452.         {
  453.         tcl_setenv(name2, Tcl_GetVar2(interp, "env", name2, TCL_GLOBAL_ONLY));
  454.         }
  455.  
  456.     if (flags & TCL_TRACE_UNSETS)
  457.         {
  458.         tcl_unsetenv(name2);
  459.         }
  460.     
  461.     return NULL;
  462.     }
  463.  
  464. /*
  465.  *----------------------------------------------------------------------
  466.  *
  467.  * EnvInit --
  468.  *
  469.  *    This procedure is called to initialize our management
  470.  *    of the environ array.
  471.  *
  472.  * Results:
  473.  *    None.
  474.  *
  475.  * Side effects:
  476.  *    Environ gets copied to malloc-ed storage, so that in
  477.  *    the future we don't have to worry about which entries
  478.  *    are malloc-ed and which are static.
  479.  *
  480.  *----------------------------------------------------------------------
  481.  */
  482.  
  483. static void
  484. EnvInit()
  485. {
  486. char    **newEnviron;
  487. int        i, length;
  488.  
  489.     if (!environ) return;
  490.  
  491.     if (environSize != 0)
  492.         {
  493.         return;
  494.         }
  495.         
  496.     for (length = 0; environ[length] != NULL; length++)
  497.         {
  498.         /* Empty loop body. */
  499.         }
  500.     
  501.     environSize = length + 5;
  502.     newEnviron = (char **) ckalloc((unsigned) (environSize * sizeof(char *)));
  503.     for (i = 0; i < length; i++)
  504.         {
  505.         newEnviron[i] = (char *) ckalloc((unsigned) (strlen(environ[i]) + 1));
  506.         strcpy(newEnviron[i], environ[i]);
  507.         }
  508.     
  509.     newEnviron[length] = NULL;
  510.     environ = newEnviron;
  511.     }
  512.